package com.tanhua.server.service;

import cn.hutool.core.collection.CollUtil;
import com.tanhua.autoconfig.templates.OssTemplate;
import com.tanhua.dubbo.api.CommentApi;
import com.tanhua.dubbo.api.MovementApi;
import com.tanhua.dubbo.api.UserInfoApi;
import com.tanhua.dubbo.api.VisitorsApi;
import com.tanhua.model.db.User;
import com.tanhua.model.db.UserInfo;
import com.tanhua.model.mongo.Comment;
import com.tanhua.model.mongo.Movement;
import com.tanhua.model.mongo.Visitors;
import com.tanhua.model.vo.ErrorResult;
import com.tanhua.model.vo.MovementsVo;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.TodayBest;
import com.tanhua.server.exceptions.BusinessException;
import com.tanhua.server.intercepror.UserHolder;
import com.tanhua.utils.Constants;
import org.apache.dubbo.config.annotation.DubboReference;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class MovementsService {

    @DubboReference
    private MovementApi movementApi;

    @Autowired
    private OssTemplate ossTemplate;

    @DubboReference
    private UserInfoApi userInfoApi;

    @Autowired//Redis对象都写泛型String,String
    private RedisTemplate<String, String> redisTemplate;

    @DubboReference
    private CommentApi commentApi;

    @Autowired
    private MqMessageService mqMessageService;
    @DubboReference
    private VisitorsApi visitorsApi;

    /**
     * 发布动态
     *
     * @param imageContent
     * @param movement
     */
    public void movements(MultipartFile[] imageContent, Movement movement) throws IOException {

        //判断用户是否冻结，根据手机号查出用户
        Long userId = UserHolder.getUserId();
        UserInfo userInfo = userInfoApi.findById(userId);
        //String userStatus = userInfo.getUserStatus();
        if (userInfo.getUserStatus().equals("2")) {//用户状态,1为正常，2为冻结
            Integer freezingRange = userInfo.getFreezingRange();
            if (freezingRange == 3) {//冻结范围，1为冻结登录，2为冻结发言，3为冻结发布动态
                throw new BusinessException(ErrorResult.myError("该账号被冻结"));
            }
        }
        //1.设置动态发布人的id
        movement.setUserId(UserHolder.getUserId());
        //2.设置发布时间
        movement.setCreated(System.currentTimeMillis());
        List<String> medias = new ArrayList<>();
        //3.将每个图片上传到阿里云，获取图片url
        for (MultipartFile file : imageContent) {
            String url = ossTemplate.upload(file.getOriginalFilename(), file.getInputStream());
            //存入到medias
            medias.add(url);
        }
        movement.setMedias(medias);
        //5.定义API完成保存，获取动态id
        String movementId = movementApi.save(movement);
        mqMessageService.sendLogMessage(UserHolder.getUserId(), "0201", "log.movement", movementId);
        //当发布动态成功之后，发送MQ消息
        mqMessageService.sendAudiMessage(movementId);//动态id
    }

    /**
     * 根据用户id查询用户发布的动态
     */
    public PageResult all(Integer page, Integer pagesize, Long userId) {
        //1.调用用户id分页查询该用户的个人动态
        List<Movement> list = movementApi.findByUserId(page, pagesize, userId);
        //判断动态是否为空
        if (CollUtil.isEmpty(list)) {
            return new PageResult();//前端页面要求，当List为空，返回一个空的PageResult
        }
        //2.查询用户的详细信息
        UserInfo userInfo = userInfoApi.findById(userId);
        List<MovementsVo> vos = new ArrayList<>();
        //3.将List<Movement>构造成List<MovementsVo>
        for (Movement movement : list) {
            MovementsVo vo = MovementsVo.init(userInfo, movement);
            String key = Constants.MOVEMENTS_INTERACT_KEY + movement.getId().toHexString();
            String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + userId;
            Boolean hasKey = redisTemplate.opsForHash().hasKey(key, hashKey);
            if (hasKey) {
                vo.setHasLiked(1);
            }
            //构造是否喜欢的返回标志
            String loveKey = Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();
            Boolean hasLove = redisTemplate.opsForHash().hasKey(key, loveKey);
            if (hasLove) {
                vo.setHasLoved(1);
            }
            vos.add(vo);
        }
        //4.封装PageResult返回
        return new PageResult(page, pagesize, 0l, vos);
    }

    /**
     * 查询好友动态
     * 根据friendId查询（可见人）
     */
    public PageResult findByFriendId(Integer page, Integer pagesize) {
        //获取查询的用户id条件
        Long friendId = UserHolder.getUserId();
        //调用API查询动态列表
        List<Movement> list = movementApi.findByFriendId(friendId, page, pagesize);
        if (CollUtil.isEmpty(list)) {
            return new PageResult();//进行一个非空判断，否则页面会出错
        }
        //3.将List<Movement>构造成List<MovementsVo>
//        返回
        return init(list, page, pagesize);
    }

    /**
     * 查询推荐动态
     */
    public PageResult findByRecommend(Integer page, Integer pagesize) {
        //1.从Redis中获取推荐的数据
        String key = "MOVEMENTS_RECOMMEND_" + UserHolder.getUserId();
        String value = redisTemplate.opsForValue().get(key);
        List<Movement> list;
        if (!StringUtils.isEmpty(value)) {
            //2.对数据进行判断，存在调用API根据动态id列表。查询数据
            //使用，进行分割
            String[] movementIds = value.split(",");
            list = movementApi.findByIds(movementIds, page, pagesize);
        } else {
            //3.如果不存在，构造模拟数据（从数据库中随机查询）
            list = movementApi.randomMovement(pagesize);
        }
        //4.将List<Movement>构造成List<MovementsVo>  返回
        return init(list, page, pagesize);
    }

    /**
     * 根据id查询动态
     */
    public MovementsVo findMovementById(String movementId) {
        //查询动态
        Movement movement = movementApi.findById(movementId);
        //查询用户信息
        UserInfo userInfo = userInfoApi.findById(movement.getUserId());
        return MovementsVo.init(userInfo, movement);
    }

    //动态-点赞
    public Integer like(String movementId) {
        //1.获取用户id
        Long userId = UserHolder.getUserId();
        Integer commentType = 1;
        //2.查询是否已经点赞（有三个查询条件参数，动态id，用户id，互动类型：1--点赞），如果已经点赞，抛出一个业务异常
        Boolean hasComment = commentApi.hasComment(movementId, userId, commentType);//true表示存在
        if (hasComment) {
            throw new BusinessException(ErrorResult.likeError());
        }
        //3.未点赞，保存数据到mongodb中
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));
        comment.setCommentType(commentType);
        comment.setUserId(userId);
        comment.setCreated(System.currentTimeMillis());
        //4.保存互动数据(需要完善方法)
        Integer count = commentApi.save(comment,2);
        //5.保存数据到Redis中
        /**
         * 使用Redis的hash数据类型     key加上动态id  hashkey前缀加用户id
         */
        //操作hash的数据结构
        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashkey = Constants.MOVEMENT_LIKE_HASHKEY + userId;
        redisTemplate.opsForHash().put(key, hashkey, "1");//Redis的key。hashkey.hashvlue

        //发送日志消息
        mqMessageService.sendLogMessage(UserHolder.getUserId(), "0203", "log.movement", movementId);

        //5.返回
        return count;
    }

    //公共的处理方法
    private PageResult init(List<Movement> list, Integer page, Integer pagesize) {
        //a：获取list集合中所有的动态发布人的id    1,2,3,4,5,6
        List<Long> userIds = CollUtil.getFieldValues(list, "userId", Long.class);
        //b：调用一次userinfoapi，根据多个id查询用户信息   Map<userId,UserInfo> map (从数据库中查询的所有用户)
        Map<Long, UserInfo> map = userInfoApi.findByIds(userIds);  //调用API+1
        //4、循环List<Movement>集合，一个Movement构建一个vo对象
        List<MovementsVo> vos = new ArrayList<>();
        for (Movement movement : list) {                                            //循环list集合
            Long userId = movement.getUserId(); //动态发布人的id
            UserInfo info = map.get(userId);
            MovementsVo vo = MovementsVo.init(info, movement);
//            //查询判断是否点赞（判断Redis中的点赞数据是否存在）
//            String key = Constants.MOVEMENTS_INTERACT_KEY + movement.getId().toHexString();//进行一个toHexString()
//            String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
//            Boolean hasKey = redisTemplate.opsForHash().hasKey(key, hashKey);
//            if (hasKey) {
//                vo.setHasLiked(1);
//            }
//            //判断是否喜欢
//            String hashKeyLove = Constants.MOVEMENT_LOVE_HASHKEY + userId;
//            Boolean hasKeyLove = redisTemplate.opsForHash().hasKey(key, hashKeyLove);
//            if (hasKeyLove) {
//                vo.setHasLoved(1);
//            }
            //构造是否点赞的返回标志
            String key = Constants.MOVEMENTS_INTERACT_KEY + movement.getId().toHexString();
            String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
            Boolean hasKey = redisTemplate.opsForHash().hasKey(key, hashKey);
            if (hasKey) {
                vo.setHasLiked(1);
            }
            //构造是否喜欢的返回标志
            String loveKey = Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();
            Boolean hasLove = redisTemplate.opsForHash().hasKey(key, loveKey);
            if (hasLove) {
                vo.setHasLoved(1);
            }
            vos.add(vo);
        }
        //5、返回值
        return new PageResult(page, pagesize, 0l, vos);
    }

    //动态--取消点赞
    public Integer dislike(String movementId) {
        //1.获取操作用户id
        Long userId = UserHolder.getUserId();
        Integer commentType = 1;
        //2.查询是否有点赞
        Boolean hasComment = commentApi.hasComment(movementId, userId, commentType);
        //3.进行判断，没有点赞操作抛出异常
        if (!hasComment) {
            throw new BusinessException(ErrorResult.disLikeError());
        }
        //3.1有点赞数据进行删除,返回最新的点赞总数
        Integer count = commentApi.delete(movementId, userId, commentType,2);
        //4.删除Redis中数据
        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + userId;
        redisTemplate.opsForHash().delete(key, hashKey);//Redis中的key，需要删除的hashkey
        mqMessageService.sendLogMessage(UserHolder.getUserId(), "0206", "log.movement", movementId);

        return count;
    }

    //动态--喜欢
    public Integer love(String movementId) {
        //1.获取用户id，互动类型
        Long userId = UserHolder.getUserId();
        Integer commentType = 3;
        //2.查询信息，看是否存在
        Boolean hasComment = commentApi.hasComment(movementId, userId, commentType);
        //3.进行判断是否存在
        if (hasComment) {
            throw new BusinessException(ErrorResult.loveError());
        }
        //没有喜欢的数据进行创建对保存
        Comment comment = new Comment();
        comment.setUserId(userId);
        comment.setCommentType(commentType);
        comment.setPublishId(new ObjectId(movementId));
        comment.setCreated(System.currentTimeMillis());
        Integer count = commentApi.save(comment,2);
        //在Redis中保存
        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashKey = Constants.MOVEMENT_LOVE_HASHKEY + userId;
        redisTemplate.opsForHash().put(key, hashKey, "3");
        mqMessageService.sendLogMessage(UserHolder.getUserId(), "0204", "log.movement", movementId);

        //返回数据
        return count;
    }

    //动态--取消喜欢
    public Integer unlove(String movementId) {
        //1.获取用户id
        Long userId = UserHolder.getUserId();
        Integer commentType = 3;
        //查询喜欢数据
        Boolean hasComment = commentApi.hasComment(movementId, userId, commentType);
        //2.判断是否有喜欢数据
        if (!hasComment) {//没有数据抛出一个异常
            throw new BusinessException(ErrorResult.disloveError());
        }
        Integer count = commentApi.delete(movementId, userId, commentType,2);
        //删除Redis中的数据
        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashKey = Constants.MOVEMENT_LOVE_HASHKEY + userId;
        redisTemplate.opsForHash().delete(key, hashKey);
        mqMessageService.sendLogMessage(UserHolder.getUserId(), "0207", "log.movement", movementId);

        return count;
    }

    //查询首页-谁看过我
    public List<TodayBest> visitors() {
        //1.获取当前用户id
        Long userId = UserHolder.getUserId();
        //2.获取查看完整访客记录（在查看完成访客记录时，将时间存入Redis）
        //获取并使用
        String key = Constants.VISITORS_USER + userId;
        String value = redisTemplate.opsForValue().get(key);
        Long time = 0l;
        if (!StringUtils.isEmpty(value)) {
            time = Long.valueOf(value);
        }
        //3.调用api查询  List<Visitors>
        List<Visitors> list = visitorsApi.findByUserId(userId, time);
        if (CollUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        //取出list中所有的visitorUserId
        List<Long> vuIds = CollUtil.getFieldValues(list, "visitorUserId", Long.class);
        Map<Long, UserInfo> map = userInfoApi.findByIds(vuIds);
        //4.循环list集合，一个Visitors转化一个TodayBeat
        List<TodayBest> vos = new ArrayList<>();
        for (Visitors visitors : list) {
            //获取访客的用户id
            Long visitorUserId = visitors.getVisitorUserId();
            //获取访客的用户信息
            UserInfo info = map.get(visitorUserId);
            //构造vo
            TodayBest vo = TodayBest.init(info, visitors);
            vos.add(vo);
        }
        //返回
        return vos;
    }
}
